fix(runtime): support CSS v-bind() on Lynx native - #144
Conversation
…tarting dev watch
- Move use-css-vars.md and LYNX-ISSUES.md from runtime/src/ to packages/vue-lynx/docs/ so rslib does not try to bundle them - Restore root package.json private: true (was accidentally set to false)
…seCssVars
Two critical fixes:
1. Add onBeforeUpdate + onMounted wrapping (matching upstream Vue):
- patchProp's SET_STYLE overwrites CSS vars on every re-render since
it doesn't know about them. Without onBeforeUpdate, CSS vars silently
vanish whenever a style binding changes but the CSS var value doesn't.
- VNode tree changes (v-if, v-for) also need CSS vars re-applied to
newly created root elements.
2. Restrict SF_ARRAY_CHILDREN walking to Fragment vnodes only:
- The standalone `if (shapeFlag & SF_ARRAY_CHILDREN)` also fired for
element vnodes with children, applying CSS vars to every descendant
element (O(N) SET_STYLE ops). Root elements are sufficient since
enableCSSInheritance cascades vars to descendants.
- Move v-bind() from "Upcoming" to "Works (requires config)" - Add required config snippet (enableCSSInlineVariables + enableCSSInheritance) - Document the known layout-property limitation - Remove the workaround snippet (no longer needed) - Update both EN and ZH versions
Revert element-registry.ts and TransitionGroup.ts type annotation changes that were rejected in PR Huxpro#122 review. Add changeset for the v-bind() CSS vars feature.
|
@KealanAU is attempting to deploy a commit to the huxpro's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
@KealanAU Thanks for the thorough investigation and the detailed PR description -- the root cause analysis of the Lynx engine's CSS var inheritance gap is spot on, and the isolation test ( I've been digging into this and wanted to share where I've landed. What we've verifiedI traced through the Lynx engine source and confirmed the bug. The root cause is that I also verified on Lynx Explorer 3.8 that same-element CSS vars (set and consumed on the same element via inline Separate fix for entry.tsThe Performance concerns with
|
|
@Huxpro I totally agree that O(N) is terrible to pay on every change. I'm happy to wait for I did think it was still an upstream issue that would need to be resolved, and had made the Thanks for splitting it off into its own PR for the other fix and the deeper dive. I was |
|
@KealanAU I just confirmed that we can make it work by fixing lynx#5889! I'll see what the nearest release I can land it in is. Thanks for the detailed issue analysis and the comprehensive CSS feature tests! I'll get back to you when it's landed.
|
Resolves conflict in entry.ts: both sides had the same fix (sourceContent.config instead of compilerOptions). Also includes the stampElementDescendants workaround removal and root-only stamping tests from the current session.
ebb4ef3 to
e80ced0
Compare
|
The engine fix is merged lynx-family/lynx#5912 and will be released in 3.8 (May) |
|
@Huxpro , Perfect, I'll remove the work around then and we can merge in May |
Engine fix lynx-family/lynx#5912 landed; root-only stamping is the correct description, not "every element".
Huxpro
left a comment
There was a problem hiding this comment.
Blocking from my side: this adds user-facing v-bind() support/docs that appear to depend on the newer Lynx engine/toolchain surface, but the compatibility baseline is still ambiguous here.
If this lands before #192, readers can reasonably take the docs as applying to the default current toolchain, while the required support may only exist on the newer release line. I think this either needs to be explicitly stacked after #192 or the docs need to state the minimum required Lynx engine/toolchain version very clearly.
Also, the linked Lynx issue references should be reconciled. I saw both lynx#5912 and lynx#5889 in the surrounding discussion/context, and that kind of mismatch makes the support story harder to trust.
…ersion Standardize all references on the fix PR (#5912, closing issue #5889) and document that v-bind() in CSS requires Lynx engine >= 3.8.1.
|
Thanks — both addressed. Issue references: the two numbers are an issue↔fix pair, not a mismatch. lynx-family/lynx#5912 is the fix PR; it closes issue #5889. Every mention in the code comments, the spec, the changeset, and the docs now reads "#5912 (closing #5889)" consistently. Compatibility baseline: you're right that this depends on the engine fix in #5912, which ships in the 3.8.1 line. I've made the requirement explicit:
|
Huxpro
left a comment
There was a problem hiding this comment.
The rewrite to root-only stamping plus engine propagation is the right long-term approach, and dropping the O(N) descendant workaround and the enableCSSInheritance requirement is a clear improvement — the new root-only tests capture the contract well. The #5912/#5889 references and the "requires engine ≥ 3.8.1" baseline now read consistently across the code, changeset, and EN/ZH docs, which resolves the earlier ambiguity.
The remaining blocker is ordering: this should land after the 3.8.1 toolchain bump in #192, which is currently still open and showing merge conflicts. Holding for #192 to merge (and to clear the prior change request) before this goes in.
Generated by Claude Code
Huxpro
left a comment
There was a problem hiding this comment.
I rechecked the current head against the tagged Lynx engine sources, and the stated minimum version is still a release blocker:
- In
3.8.1,FiberSetInlineStylesclears/updates inline CSS variables but does not collect changed variables, dirty the element, or recursively invalidate descendants: https://github.com/lynx-family/lynx/blob/3.8.1/core/runtime/lepus/bindings/renderer_functions.cc#L3826-L3878 - Those propagation steps (
changed_css_vars,MarkCustomPropertiesDirty,MarkStyleDirty, andRecursivelyMarkChildrenCSSVariableDirty) first appear in the3.9.0tagged source: https://github.com/lynx-family/lynx/blob/3.9.0/core/runtime/lepus/bindings/renderer_functions.cc#L4085-L4124
Please address these points before approval:
- Change the compatibility docs, changeset, and PR description to require Lynx engine >= 3.9.0, unless there is a specific tagged 3.8.x backport that contains the same propagation code.
- Set
enableCSSInheritance: falsein thecss-featuresexample used to validate this feature. It is currentlytrue, so the example andCSSInheritanceTest.vuecan mask whether #5912 propagation works without inheritance mode. - Re-run the native reactive-update verification on the documented minimum engine with
enableCSSInlineVariables: trueandenableCSSInheritance: false, confirming a descendant consumingvar(...)updates. The localuse-css-vars.spec.tscoverage only proves that the BG runtime emits rootSET_STYLEops; it cannot prove the native engine cascades or invalidates descendant styles. - Update the root-only test comments so they do not present native propagation as something that test itself verifies.
This PR also depends on #192, so its branch will need to be refreshed after that toolchain change lands and CI rerun on the resulting head.
The #5912 propagation code (changed_css_vars, MarkCustomPropertiesDirty, RecursivelyMarkChildrenCSSVariableDirty) first appears in the 3.9.0 tag; 3.8.1 lacks it and no later 3.8.x tag exists. - Bump minimum engine to 3.9.0 in EN/ZH docs, changeset, and code comments - Set enableCSSInheritance: false in css-features example so it cannot mask engine-level custom property propagation - Reword root-only spec comments: they verify BG op emission only, not native descendant cascade
|
Thanks for catching the version gap. All four points are addressed on the latest head.
CleanShot.2026-07-17.at.21.47.45.mp4I also merged latest main into the branch and all suites pass. Two notes for follow-up: #192 currently targets the 3.8.1 toolchain line, which is below the new minimum, so it needs to move to 3.9.0 before the final refresh and CI rerun. Separately, the lynxjs.org quick-start currently serves the 3.8.1 Explorer download, so developers following it will land one version below the minimum; the docs could point at the GitHub 3.9.0 release instead. |
|
Status update (2026-08-17): the implementation branch is still textually mergeable, and the author’s latest comment supplies the requested 3.9.0 native verification with enableCSSInlineVariables=true and enableCSSInheritance=false. However this remains not ready to merge:\n\n1. The formal review decision is still CHANGES_REQUESTED.\n2. This PR explicitly depends on #192; #192 has now been refreshed onto current main but cannot merge until the maintainer-specified Vapor 0.6.0 release order is satisfied.\n3. After #192 lands, this branch must be refreshed onto that resulting main, CI rerun, and the reviewer must re-review/dismiss the stale change request on the refreshed head.\n\nNo code change is appropriate on this branch before #192 lands; doing so would validate against the wrong toolchain baseline. |

Summary
Adds Background-Thread-safe support for
v-bind()in Vue<style>blocks on Lynx native.enableCSSInheritanceguidance.Compatibility
changed_css_vars,MarkCustomPropertiesDirty,RecursivelyMarkChildrenCSSVariableDirtyinFiberSetInlineStyles, closing lynx#5889). The 3.8.1 tag lacks it and no later 3.8.x tag exists. On earlier engines the vars are stamped on the root but never reach descendants. Stated in the EN + ZH compatibility docs and the changeset.enableCSSInlineVariables: true.enableCSSInheritanceis not required — the css-features example now sets it tofalseso inheritance mode cannot mask whether #5912 propagation works on its own.Verification
pnpm test:localinpackages/upstream-tests— verifies the BG runtime emits root-onlySET_STYLEops (mount, reactive update, fragments, v-show). It does not verify native descendant cascade; that is engine behavior.enableCSSInlineVariables: trueandenableCSSInheritance: false, confirming a descendant consumingvar(...)updates reactively. The videos below were recorded withenableCSSInheritance: trueand will be replaced.CleanShot.2026-04-05.at.15.29.59.mp4
CleanShot.2026-04-05.at.15.07.14.mp4